\graphicspath{{Abbildungen/}}

\onehalfspacing

\lstdefinelanguage{launch}
{
   morekeywords={launch,node,pkg,type,name,output,respawn,param,value,remap,from,to,required},
   morecomment=[s][\color{gray}]{[.}{.]}
}
\lstdefinelanguage{comments}
{
   morecomment=[s][\color{gray}]{[.}{.]}
}
\lstdefinelanguage{pseudocode}
{
   morekeywords={if,else,endif,for,all,end,return},
}

\chapter{Objekterkennung und "~verfolgung auf einem mobilen Roboter}

\section{Einführung}

Im nachfolgenden Projektbericht wird ein Verfahren für die Objekterkennung und "~verfolgung von
einem mobilen Roboter aus beschrieben.

\subsection{Aufgabenstellung}
Ein mobiler Roboter mit dem installierten Roboter-Framework \textit{Robot
Operating System (ROS)} und einer handelsüblichen Webcam des Typs
\textit{Logitech Quickcam Pro 9000} soll im Fahrbetrieb Objekte -- vollflächig ausgefüllte rote Kreise auf
weißem Hintergrund -- erfassen und klassifizieren. Die Objekte sind hierbei stationär an
Wänden angebracht. Dabei ist zu berücksichtigen, dass Objekte nicht mehrmals
erkannt werden und das Kamerabild mit dem erkannten Objekt abgespeichert wird.

\subsection{Vorgehensweise}
Das zuvor beschriebene Problem wurde zunächst analysiert und in zwei wesentliche Teilaufgaben unterteilt.
\begin{itemize}
	\item Im ersten Teilmodul wird die \textbf{Anbindung und Kommunikation mit ROS} umgesetzt. Hierfür wird ein neues ROS-Paket erstellt, in dem Nodes\footnote{Ausführbare Datei in ROS (siehe auch Abschnitt~\ref{sec:AnbindungKommunikationMitRos})} für die Kameraanbindung, die Objekterkennung und "~verfolgung und die Anbindung an das Visualisierungstool \textit{RViz} realisiert wurden.
	\item Das zweite große Teilmodul umfasst die Bildverarbeitungsalgorithmen des oben genannten Nodes zur \textbf{Objekterkennung und "~verfolgung}\footnote{Im Folgenden wird auch die gleichwertige, englische Bezeichnung \textit{tracking} verwendet.}.
\end{itemize}

Zunächst wird die Implementierung der Objekterkennung und "~ver"-fol"-gung erläutert. Im Anschluss daran wird die Integration in das Roboter-Frame"-work ROS dargestellt.

\section{Objekterkennnung und "~verfolgung}
\label{ObjektErkenn}

In diesem Abschnitt werden die Bildverarbeitungsschritte für die Objekterkennung beschrieben. Hierfür kommt das Bildverarbeitungs-Framework \textit{OpenCV} zum Einsatz.
Die Objekterkennungssoftware wird von ROS in festen Intervallen mit dem jeweils aktuellen Kamerabild versorgt. Danach wird das Bild mit den folgenden Bildverarbeitungsoperationen für die nachfolgende Objekterkennung aufbereitet. Anschließend wird das eingelesene Bild auf dem Bildschirm angezeigt, erkannte Objekte werden entsprechend gekennzeichnet. Nach dem ein Objekt von der Objektverfolgung erfolgreich getrackt wurde, wird ein Ergebnisbild abgespeichert. In den folgenden Abschnitten werden die einzelnen Teilschritte näher erläutert.

\subsection{Objekterkennung}
\label{sec:Objekerkennung}

\subsubsection{Vorverarbeitung der aufgenommenen Kamerabilder}
\label{Maske}
Die zu erkennenden Objekte sind an den Wänden, direkt über dem Boden angebracht. Aus diesem Grund können irrelevante Bildbereiche bei der Auswertung außer Acht gelassen werden. Daher wird zunächst mittels einer Maske der unwichtige Bildbereich ausgeblendet (Listing~\ref{lst:maskierung} und Abbildung~\ref{fig:Maske}).

\begin{lstlisting}[caption={Maskierung des Kamerabildes in OpenCV.}, label={lst:maskierung},language=C++,alsolanguage=comments, tabsize=2, basicstyle=\footnotesize, frame=single]
[...]
	applyFloorMask(mat);
[...]
\end{lstlisting}

\begin{figure}[!htb]
	\centering
	\includegraphics[width=0.6 \textwidth]{Maske.png}
	\caption{Kamerabild nach der Maskierung}
	\label{fig:Maske}
\end{figure}

Für die Festlegung des geeignetsten Farbraumes wurden zunächst, während einer manuell gesteuerten Roboterfahrt, Referenzbilder aufgenommen. Hierbei wurden folgende Farbräume auf ihre Eignung bezüglich der späteren Segmentierung untersucht.

\begin{itemize}
	\item RGB-Farbraum: Rotkanal minus die Summe aus Grün- und Blaukanal und
	anschließende Segmentierung
	\item HSV-Farbraum: Segmentierung des Sättigungskanals
	\item YCrCb-Farbraum: Segmentierung des Cr-Kanals
\end{itemize}

Das beste Ergebnis lieferte der YCrCb-Farbraum. Beim YCrCb-Farbmodell sind die Farbinformationen in die Grundhelligkeit \textit{Y} und die zwei Farbkomponenten \textit{Cr} (Red-Green Chrominance) und \textit{Cb} (Blue-Yellow Chrominance) aufgeteilt (Abbildung~\ref{fig:YCrCb_Farbraum}). Das Kamerabild wird nach der Maskierung vom RGB- in den YCrCb-Farbraum konvertiert (Listing~\ref{lst:farbraum_konvertierung}). Für die nachfolgende Segmentierung wird nur der Cr-Kanal verwendet (Abbildung~\ref{fig:Cr_Kanal}).

\begin{figure}[h]
  \begin{center}
    \subfigure[]{
      \includegraphics[width=0.41 \textwidth]{ycrcb.png}
      \label{fig:YCrCb_Farbraum}
    }\hfill
    \subfigure[]{
      \includegraphics[width=0.55 \textwidth]{CRKanal.png}
      \label{fig:Cr_Kanal}
    }
\caption[YCrCb-Farbraum; Cr-Kanal des Bildes]{\subref{fig:YCrCb_Farbraum} YCrCb-Farbraum. Quelle:~\cite{WIKI_YCrCbFarbraum}. \subref{fig:Cr_Kanal} Cr-Kanal des Bildes.}
  \label{fig:YCrCb_Farbraum_CrKanal}
\end{center}
\end{figure}

%\begin{figure}[h]
%	\centering
%	\includegraphics[width=0.6 \textwidth]{CRKanal.png}
%	\caption{Cr-Kanal des Bildes}
%	\label{fig:Cr}
%\end{figure}

\begin{lstlisting}[float, caption={Farbraumkonvertierung in OpenCV.}, label={lst:farbraum_konvertierung}, language=C++,alsolanguage=comments, tabsize=2, basicstyle=\footnotesize, frame=single]
[...]
	cvtColor(mat, outYC, CV_BGR2YCrCb);
	split(outYC, YCcolors);
[...]
\end{lstlisting}

\subsubsection{Segmentierung}
\label{Segmentierung}

Nachfolgend wird auf den Cr-Kanal eine Schwellenwertsegmentierung angewendet (Listing~\ref{lst:segmentierung}). Der Threshold wurde auf den Wert 150 festgelegt, dieser wurde heuristisch ermittelt. Abbildung~\ref{fig:Segmentierung} zeigt das Bild nach der Segmentierung. Auf dieser ist zu erkennen, dass eine alleinige Segmentierung nicht ausreichend ist, da auch unerwünschte Bereiche und Objekte (z.B. Spiegelungen) segmentiert werden. Daher erfolgt im Anschluss eine Blob-Analyse.

\begin{lstlisting}[ caption={Schwellenwertsegmentierung des Bildes in OpenCV.}, label={lst:segmentierung}, language=C++,alsolanguage=comments, tabsize=2, basicstyle=\footnotesize, frame=single, breaklines=true]
[...]
	threshold(YCcolors[2], redContent, RED_SEGMENTATION_THRESH, 255, CV_THRESH_BINARY);
[...]
\end{lstlisting}

%\begin{figure}[!htb]
%	\centering
%	\includegraphics[width=0.6 \textwidth]{Segmentierung.png}
%	\caption{Bild nach der Segmentierung}
%	\label{fig:Segmentierung}
%\end{figure} 


\begin{figure}[h]
  \begin{center}
    \subfigure[]{
      \includegraphics[width=0.48 \textwidth]{Segmentierung.png}
      \label{fig:Segmentierung}
    }\hfill
    \subfigure[]{
      \includegraphics[width=0.48 \textwidth]{Blob.png}
      \label{fig:Blob}
    }
\caption[Bild nach Segmentierung, Blob-Analyse und Filterung.]{\subref{fig:Segmentierung} Bild nach der Schwellenwertsegmentierung. \subref{fig:Blob} Ergebnis der anschließenden Blob-Analyse mit Filterung.}
  \label{fig:Segmentierung_Blob}
\end{center}
\end{figure}


\subsubsection{Blob-Analyse}
\label{Blobanalyse}

Nach der Segmentierung wird eine Blob-Analyse zur Erkennung von zusammenhängenden Regionen auf das Bild angewendet (Listing~\ref{lst:blob_analyse}). Anschließend werden die einzelnen Blobs anhand ihrer Pixelanzahl gefiltert. Für die Weiterverarbeitung werden nur Blobs beachtet, die größer als 200 Pixel und kleiner als 7000 Pixel sind. Dadurch werden unerwünschten Bereiche und Objekte nicht weiter berücksichtigt (Abbildung~\ref{fig:Blob}). Ein weiterer Effekt, der sich durch diese Filterung ergibt ist, dass Objekte erst ab einem bestimmten Mindestabstand zum Roboter erkannt werden.

\begin{lstlisting}[ caption={Blob-Analyse und Filterung in OpenCV.}, label={lst:blob_analyse}, language=C++,alsolanguage=comments, tabsize=2, basicstyle=\footnotesize, frame=single]
[...]
	blobAnalysis(redContent);
	filterUnprocessedMarks();
[...]
\end{lstlisting}

%\begin{figure}[!htb]
%	\centering
%	\includegraphics[width=0.6 \textwidth]{Blob.png} 
%	\caption{Bild nach der Blob-Analyse und der Filterung}
%	\label{fig:Blob}
%\end{figure}

%%%%%%%%%%%%%%%%%%%

\subsection{Objektverfolgung}

In der Aufgabenstellung wird gefordert pro erkanntem Objekt ein Ergebnisbild anzufertigen. Hierzu ist es notwendig die einzelnen Objekte über mehrere Bilder hinweg zu verfolgen. Anderenfalls kann der unerwünschte Fall eintreten, dass ein Objekt mehrfach als Ergebnis
gemeldet wird.
\par
Ausgehend von der vorhergehenden Blob-Analyse wird für jeden Blob ein Objekt der Klasse \textit{Mark} erstellt. Jedes Mark enthält folgende Informationen.

\begin{itemize}
	\item Rundheit
	\item Fläche
	\item Umfang
	%\item Bewegungsvektor (initial 0)
	\item Position des Mittelpunktes
	\item Orientierung (linke oder rechte Wand)
\end{itemize}

An den Tracker wird jedes Bild übergeben und eine Liste von Marks erstellt. Danach werden die Marks 
zweier aufeinanderfolgender Bilder auf ihre Übereinstimmung verglichen. Listing~\ref{lst:pseudocode_objektverfolgung} zeigt den Pseudocode des Algorithmuses. Die Vergleichsfunktion \textit{compare()} gibt hierbei einen ganzzahligen Wert zurück der umso größer ist, je mehr Merkmale zueinander passen. Dabei werden folgende Merkmale berücksichtigt und unterschiedlich gewichtet.

\begin{lstlisting}[ caption={Pseudocode der Objektverfolgung (Tracking).}, label={lst:pseudocode_objektverfolgung}, language=pseudocode,tabsize=2,basicstyle=\footnotesize, frame=single]
if(isEmpty(TrackedBlobs))
  TrackedBlobs = NewBlobs;
endif;
for all NewBlobs
  for all TrackedBlobs
    result = compare(NewBlob[i], TrackedBlob[j]);
    if(result > minResult)
      TrackedBlob[j] = NewBlob[i];
    else
      addToTrackedBlobs(NewBlob[i]);
    endif;
  end;
end;
for all TrackedBlobs
  if(notUpdated(TrackedBlob[k]))
    return TrackedBlob[k].image;
  endif;
end;
\end{lstlisting}

\begin{itemize}
\item Die \textbf{Orientierung} wird bei der ersten Erkennung eines Marks ermittelt. Dabei wird
zwischen linker und rechter Wand unterschieden. Falls beide Marks eine
identische Orientierung besitzen, sie sich also auf der gleichen Flurseite
befinden, wird dies mit 40 Punkten gewichtet.
\item \textbf{Position:} Hierbei werden die Koordinaten der X-Achse der beiden Punkte verglichen. Falls die Differenz kleiner einem festgelegten Grenzwert ist, so wird dies mit 20
Punkten gewichtet. Hierbei ist zu beachten, dass der Grenzwert an die Bildrate
und die Geschwindigkeit des Roboters angepasst werden muss. Mit niedrigerer
Bildrate und höherer Robotergeschwindigkeit sind die Positionsänderungen eines Marks von
einem Bild zum nächsten größer, es muss also ein größerer Grenzwert eingestellt werden.
\item Die \textbf{Fläche} eines zu trackenden Marks
wächst bei Vorwärtsfahrt von Bild zu Bild an.
Der Zuwachs der Fläche wird mit einer Toleranz von 10\% betrachtet.
Ein Mark darf also zwischen zwei Bildern auch auf 90\% seiner
vorherigen Größe schrumpfen, das mögliche Wachstum ist jedoch unbeschränkt. Bedingt durch Rauschen und automatisches
Anpassen der Belichtungszeiten der Kamera schwankt die gemessene Fläche selbst
bei Stillstand des Roboters leicht.
Durch die Toleranz wird sicher gestellt, dass der Tracker ein Mark auch weiter verfolgen
kann wenn der Roboter stillsteht. Stimmen die Flächen nach diesen Vorgaben überein wird dies mit 10 Punkten gewichtet.
\item Durch die Vorwärtsbewegung des Roboters wird der Blickwinkel auf die
Markierungen stetig steiler. Die \textbf{Rundheit} des Marks nähert sich dadurch der
eines perfekten Kreises an, erreicht diesen aber nie. Die Rundheit errechnet sich nach:
\begin{equation*}
\text{Rundheit} = \frac{ \text{Umfang}^2 }{ \text{Fläche}  }
\end{equation*}
Der Wert wird kleiner, je näher der Roboter sich an der Markierung
befindet. Ein perfekter Kreis besitzt einen Rundheitswert von 12,56.
Stimmen die Rundheitswerte nach diesen Vorgaben überein, so wird dies mit 10
Punkten gewichtet.
\end{itemize}

Der Grenzwert, ab dem der Tracker zwei Marks als identisch betrachtet, beträgt 70
Punkte. Die Objekte müssen sich also auf der gleichen Flurseite befinden und entweder
Rundheit und Fläche oder die Positionsänderung muss sich nach den oben
beschriebenen Vorgaben verhalten. Werden zwei Marks vom Tracker als gleichwertig
erkannt, wird das alte Mark mit den Daten des Neueren aktualisiert.


\subsubsection{Ergebnisbild}
Ein Ergebnisbild (Abbildung~\ref{fig:Ergebnis}) mit dem erkannten Objekt wird erstellt, sobald folgende Kriterien
erfüllt sind.

\begin{itemize}
	\item Das Mark wurde über mindestens zwei Bilder hinweg getrackt.
	\item Das Mark wurde über mindestens fünf Bilder hinweg nicht mehr
	aktualisiert.
	\item Die letzte bekannte Position des Marks war am Rand des Bildes.
\end{itemize}

\begin{figure}[!htb]
	\centering
	\includegraphics[width=0.6 \textwidth]{Ergebnis2.png}
	\caption[Ergebnisbild der Objektverfolgung]{Ergebnisbild der Objektverfolgung. Das rechte Objekt wurde noch nicht erkannt, da es von dem Roboter zu weit entfernt ist.}
	\label{fig:Ergebnis}
\end{figure}


%\subsection{Standard Anwendungsfall}
%Der Standard Anwendungsfall setzt sich aus folgenden Schritten zusammen:
%
%\begin{enumerate}
%  \item Der Roboter bewegt sich mit gleichförmiger Geschwindigkeit den Gang
%  entlang.
%  \item In einiger Entfernung taucht eine Markierung auf. Diese wird zunächst
%  nicht erkannt, da sie erst ab einer bestimmten Größe nicht mehr durch die
%  Blobanalyse herausgefiltert wird.
%  \item Die Markierung ist groß genug um den Filter der Blobanalyse zu
%  passieren.
%  \item Im folgenden Bild wird die Markierung aufgrund ihrer Merkmale vom
%  Tracker wieder erkannt.
%  \item Sobald der Roboter die Markierung passiert hat wird das zugehörige Mark
%  nicht mehr aktualisiert.
%  \item Es wird überprüft ob die letzte getrackte Position des Marks am Rand des
%  Bildes war. Falls ja, wird ein Ergebnisbild erzeugt und ausgegeben.
%\end{enumerate}


\section{Anbindung und Kommunikation mit ROS}
\label{sec:AnbindungKommunikationMitRos}

In diesem Teil wird die Anbindung der in Abschnitt~\ref{ObjektErkenn} aufgeführten OpenCV-Algorithmen in ROS aufgezeigt. Die Ergebnisse der Objekterkennung- und verfolgung werden im Visualisierungstool RViz präsentiert. Hierzu wird nach dem Auffinden eines Objektes die aktuelle Roboterposition mit einem Marker in der Karte dargestellt. 

%\subsection{Über ROS}

Eine ausführbare Datei, die mit dem ROS-Framework verbunden ist, wird \textit{Node} genannt.
Nodes kommunizieren über \textit{Nachrichten (Messages)} miteinander die über \textit{Topics} ausgetauscht werden. Hierbei verwendet ROS das \textit{Publisher-Subscriber}-Ent"-wurfs"-muster \cite{GOF}. Nodes die Nachrichten veröffentlichen besitzen eine Publisher-Funktionalität. Nodes die Nachrichten empfangen besitzen eine Subscriber-Funk"-ti"-o"-nalität. Eine Node kann auch beide Funktionalitäten zur gleichen Zeit besitzen. Einzelheiten über die in ROS verwendeten Techniken können den ROS-Tutorials entnommen werden \cite{ROS_TUT_PUB_SUSCRB}.

Die in diesem Projekt realisierte Software besteht aus vier Nodes, die jeweils unterschiedliche Funktionen erfüllen (Abbildung~\ref{fig:nodeMap}).

\begin{itemize}
  \item Die \textbf{seekdot\_node} implementiert die im ersten Teilmodul beschriebenen Bildverarbeitungsverfahren.
  \item Die \textbf{seekdot\_interface}-Node stellt eine Schnittstelle zu RViz dar und bietet dem Anwender eine Möglichkeit die Ergebnisse zu betrachten.
  \item Der \textbf{image\_saver} legt zuvor selektierte Ergebnisbilder als JPEG-Dateien ab.
  \item Die \textbf{image\_view} zeigt dem Anwender ein von ihm gewähltes Ergebnisbild.
\end{itemize}

Damit diese Nodes richtig miteinander kommunizieren können, müssen sie gestartet und konfiguriert werden. Hierfür wird das von ROS zur Verfügung gestellte Tool \textit{roslaunch} verwendet. Dieses Werkzeug erwartet eine XML-Datei und startet die darin gelisteten Nodes mit den festgelegten Parametern. Eine ausführliche Beschreibung zu \textit{roslaunch} findet sich in dem ROS-Tutorial \textit{"`Using rxconsole and roslaunch"'} \cite{ROS_ROSLAUNCH}.

\begin{figure}[htb]
	\centering
	\includegraphics[width=0.95\textwidth]{node_map2.png}
	\caption[Übersicht über die relevanten ROS-Nodes und ROS-Topics]{Übersicht über die relevanten ROS-Nodes (Knoten) und ROS-Topics (Kanten). Die Topics verbinden die Nodes miteinander.}
	\label{fig:nodeMap}
\end{figure}

\subsection{Kameraanbindung}

Die Aufnahme der Roboterumgebung erfolgt mit einer handelsüblichen Webcam des Typs \textit{Logitech Quickcam Pro 9000}. Zunächst holt sich ROS -- für die spätere Objekterkennung und "~verfolgung -- das von der Kamera aufgenommene Bild.  Hierfür existiert bereits das fertig implementierte ROS-Paket \textit{usb\_cam} mit dem ROS-Node \textit{usb\_cam\_node}.  Der Start der ROS-Node erfolgt durch das Launch-File (Listing~\ref{lst:usb_cam}).

\begin{lstlisting}[language=XML,alsolanguage=launch,caption={Ausschnitt aus dem Launch-File -- \textit{usb\_cam\_node}.}, label={lst:usb_cam}, tabsize=2, basicstyle=\footnotesize, frame=single]
<launch>
[...]
	<node pkg="usb_cam" type="usb_cam_node" name="logitech_usb_webcam" 
	output="screen" respawn="true" >
 		<param name="video_device" type="string" value="/dev/video1" />
 		<param name="pixel_format" type="string" value="yuyv" />
	</node>
[...]
</launch>
\end{lstlisting}

Das <node>-Tag erwartet die Attribute \textit{pkg}, \textit{type}, \textit{name}, \textit{output} und \textit{respawn}.

\begin{itemize}
  \item Das \textbf{pkg}-Attribut gibt den Ordner an, in dem ROS die ausführbare Datei findet.
  \item Die Node selbst wird durch das \textbf{type}-Attribut spezifiziert.
  \item Das \textbf{name}-Attribut legt einen eindeutigen Instanznamen für ROS fest.
  \item Mit dem \textbf{output}-Attribut wird ROS mitgeteilt, wohin die Ausgaben des Prozesses erfolgen soll, in diesem Fall durch den Wert \textit{screen} in das aktuelle Konsolenfenster.
  \item Das Attribut \textbf{respawn = ``true''} veranlasst ROS, die Node automatisch wieder neu zu starten, sofern diese unerwartet beendet wird.
\end{itemize}

Innerhalb des <node>-Tags können mit dem <param>-Tag verschiedene Parameter an die Node übergeben werden. Mit dem Parameter \textit{video\_device} wird die Gerätedatei der Kamera angegeben. Der Parameter \textit{pixel\_format} legt das verwendete Videoformat fest. Nach dem Starten des Launch-Files existiert die ROS-Node \textit{logitech\_usb\_webcam} und über das Topic \textit{image\_raw} stellt diese das Kamerabild zur Verfügung.


\subsection{Bildverarbeitung}

Die in Abschnitt~\ref{ObjektErkenn} beschriebenen Bildverarbeitungs-Algorithmen sind in \textit{seekdot\_node} implementiert.
Auf Grund des Quellcodeumfangs werden nachfolgend nur die Codezeilen erläutert, die zum Verständnis des Ablaufs beitragen.

Die \textit{seekdot\_node} erhält über das \textit{image\_raw}-Topic das jeweils aktuelle Kamerabild in einem komprimierten ROS-spezifischen Format.
Zur Kodierung bzw. Dekodierung dieser Kamerabilder werden die Subscriber bzw. Publisher des \textit{image\_trans"-port}-Pakets eingesetzt \cite{RVIZ_IMAGE_TRANSPORT}.
Für die weitere Verarbeitung mit OpenCV müssen die Bilder zunächst in ein OpenCV-konformes Datenformat umgewandelt werden.
Hierfür wird die \textit{OpenCV-Bridge} aus dem ROS-Paket \textit{vision\_opencv} verwendet \cite{RVIZ_VISION_OPENCV}.

Die Methode \textit{processImage} führt die erwähnten Konvertierungsoperationen durch und verarbeitet die empfangenen Bilder (Listing~\ref{lst:processImage01}).

\begin{lstlisting}[caption={Ausschnitt aus Methode \textit{processImage}.}, label={lst:processImage01}, language=C++,alsolanguage=comments, tabsize=2, basicstyle=\footnotesize, frame=single, breaklines=true]
void Seeker::processImage( const sensor_msgs::ImageConstPtr& msg, const sensor_msgs::CameraInfoConstPtr& camera_info){
[...]
	// OpenCV-Bridge anlegen
	sensor_msgs::CvBridge img_bridge;
	// In IplImage umwandeln
	img_bridge.fromImage(*msg, "rgb8");
[...]
}
\end{lstlisting}

Detektiert der Objekterkennungs und -verfolgungsalgorithmus ein Objekt, so publiziert die Node das Bild und die aktuelle Roboterposition (Listing~\ref{lst:processImage02}).

\begin{lstlisting}[caption={Ausschnitt aus Methode \textit{processImage}.}, label={lst:processImage02}, language=C++,alsolanguage=comments, tabsize=2, basicstyle=\footnotesize, frame=single, breaklines=true]
[...]
	if(found){
		[...]
		IplImage ipl_out=out.operator _IplImage();
		[...]
		sensor_msgs::Image img_out=*img_bridge.cvToImgMsg(&ipl_out, "rgb8");
		[...]
		nav_msgs::Odometry pose=this->last_pose;
		pose.header.stamp=info_out.header.stamp;
		[...]
		pose_out.publish(pose);
		[...]
		image_circle.publish(img_out,info_out,info_out.header.stamp);
	}
[...]
\end{lstlisting}

Die \textit{seekdot\_node} wird über das Launch-File gestartet (Listing~\ref{lst:seekdotNode}).

\begin{lstlisting}[language=XML,alsolanguage=launch,caption={Ausschnitt aus dem Launch-File -- \textit{seekdot\_node}.}, label={lst:seekdotNode}, tabsize=2, basicstyle=\footnotesize, frame=single, breaklines=true]
<launch>
[...]
	<node pkg="seekdot_node" type="seekdot_node" name="seekdot_node" 
		 output="screen" respawn="true">
		<remap from="pose_in" to="/pose" />
		<remap from="image" to="logitech_usb_webcam/image_raw" />
	</node>
[...]
</launch>
\end{lstlisting}

\subsection{Darstellung der Ergebnisse in RViz}

Für die Darstellung von erkannten Objekten werden sogenannte \text{Marker} eingesetzt. Marker werden vom Visualisierungstool \textit{RViz} angeboten um besondere Punkte auf Karten bzw. im Raum zu kennzeichnen \cite{RVIZ_MARKER_WIKI}. Abbildung~\ref{fig:InterfMarkerGest} zeigt exemplarisch eine Karte mit eingezeichneten Markern.
Der Quelltext wird hier aufgrund des Umfangs nicht dargestellt, sondern nur dessen allgemeine Funktionsweise beschrieben.

%\begin{figure}[htbp]
%	\centering
%	\includegraphics[width=0.6 \textwidth]{Karte.jpg}
%	\caption{Exemplarische Karte mit eingezeichneten Markern.}
%	\label{fig:InterfMarkerGest}
%\end{figure}


\begin{figure}[h]
  \begin{center}
    \subfigure[]{
      \includegraphics[width=0.47 \textwidth]{Karte_01.png}
      \label{fig:InterfMarkerGest}
    }\hfill
    \subfigure[]{
      \includegraphics[width=0.49 \textwidth]{gestapelteMarker_01.png}
      \label{fig:gestapelteMarker}
    }
\caption[Karte mit mehreren Markern und Kontextmenü.]{\subref{fig:InterfMarkerGest} Exemplarische Karte mit eingezeichneten Markern. \subref{fig:gestapelteMarker} Gestapelte Marker mit Kontextmenü.}
  \label{fig:Marker_Karte_Gestapelt}
\end{center}
\end{figure}



\subsubsection{Funktionsweise}

Die Node \textit{seekdot\_interface} bildet die Kommunikationsschnittstelle zwischen erkannten Objekten und RViz.
Diese erstellt einen interaktiven Marker an der aktuellen Position des Roboters, sobald sie ein Ergebnisbild empfängt.
Der Marker wird durch einen flachen, roten Zylinder in der Karte dargestellt.  
Werden mehrere Ergebnisbilder an der gleichen Position empfangen, so werden die Marker gestapelt. 
Dadurch ist ein Zugriff auf alle Ergebnisbilder möglich (Abbildung~\ref{fig:gestapelteMarker}).
Jeder Marker ist mit einem Kontextmenü versehen, das dem Anwender folgende Funktionen bietet.

\begin{itemize}
	\item \textbf{Anzeigen} (display) der entsprechenden Kameraaufnahme eines Markers.
	\item \textbf{Speichern} (save) der entsprechenden Kameraaufnahme eines Markers.
	\item \textbf{Löschen} (delete) des Markers und der zugehörigen Kameraaufnahme.
\end{itemize}

Beim Betätigen des Menüpunktes \textit{Speichern} wird die entsprechende Kameraaufnahme über das Topic \textit{seekdot\_interface/save} veröffentlicht. Die \textit{image\_saver}-Node ist damit verbunden und speichert jedes Bild, das über dieses Topic eintrifft. Als Dateiname wird die Position des Markers auf der Karte verwendet.

Die Funktion \textit{Anzeigen} veröffentlicht die entsprechende Kameraaufnahme über das Topic \textit{seekdot\_interface/display}. 
Mit dieser ist die \textit{image\_view}-Node verbunden. Letztere erstellt daraufhin ein Fenster in RViz, in dem das Kamerabild angezeigt wird.

Damit die Marker in RViz sichtbar sind, muss im Display-Fenster das \textit{Interactive Marker Display} hinzugefügt und auf das Topic \textit{seekdot\_interface/dot\_locations/update} gesetzt werden. 

%\subsubsection{Interface Funktionen}
%Die empfangenen Bilder werden innerhalb der Node in einem
%ImageTransport-Nachrichten-Array gespeichtert. Durch Auswählen des ``Delete''
%Eintrags im Kontextmenü eines Markers, wird die Markierung, das zugehörige Bild
%und der Marker gelöscht. Wählt der Benutzer den Punkt Display oder Save wird
%die gespeicherte Message entweder über das Topic ``display''
%oder über ``save'' publiziert. 

%\begin{figure}[htbp]
%	\centering
%	\includegraphics[width=0.6 \textwidth]{gestapelteMarker.jpg}
%	\caption{Gestapelte Marker mit Kontextmenü.}
%	\label{fig:gestapelteMarker}
%\end{figure}

Die Nodes werden wie die Vorherigen über das Launch-File gestartet (Listing~\ref{lst:seekdotInterface}).
\begin{lstlisting}[language=XML,alsolanguage=launch,label={lst:seekdotInterface},caption={Ausschnitt aus dem Launch-File -- \textit{seekdot\_interface}.},tabsize=2,basicstyle=\footnotesize,frame=single]
<launch>
[...]
	<node pkg="seekdot_interface" type="seekdot_interface" 
	      name="seekdot_interface" output="screen" required="true">
		<remap from="image" to="seekdot_node/circles/image_raw" />
		<remap from="pose" to="seekdot_node/pose_out" />
		<param name="marker_frame_id" type="string" value="/odom" />
	</node>
	
	<node pkg="image_view" type="image_view" name="SeekDot_Display" 
		  output="screen" required="true"  args="compressed">
		<remap from="image" to="seekdot_interface/display/image_raw" />
	</node>

	<node pkg="image_view" type="image_saver" name="image_saver" 
	      output="screen" respawn="true">
		<remap from="image" to="seekdot_interface/save/image_raw" />
	</node>
[...]
</launch>
\end{lstlisting}

\section{Zusammenfassung und Ausblick}

\subsection{Zusammenfassung}

Im vorliegenden Projektbericht wird ein Verfahren für die Erfassung und Verfolgung von stationären Objekten von einem mobilen Roboter aus beschrieben. Hierbei kommt auf dem mobilen Roboter das Framework \textit{Robot Operating System (ROS)} zum Einsatz. Die Objekterkennung erfolgt mit einer handelsüblichen Webcam und dem Softwarepaket \textit{OpenCV}, das hierfür mit ROS kommuniziert. Als zweidimensionale Objekte kommen jeweils vollflächig gefüllte, rote Kreise auf einem weißen Hintergrund zum Einsatz, die stationär an Wänden angebracht sind. Damit ein Objekt nicht mehrmals erfasst wird wurde weiterhin eine Objektverfolgung implementiert. Im ROS-Visualisierungstool \textit{RViz} werden die erfassten Objekte durch interaktive Marker in einer virtuellen Umgebungskarte dargestellt und können dann abgespeichert werden.
\par
Die Aufgabe wurde erfolgreich gelöst und implementiert. Die zu erkennenden Objekte werden unter den getroffenen Annahmen zuverlässig erkannt. Dicht zusammen angeordnete Objekte können ebenfalls problemlos unterschieden werden.

\subsection{Ausblick}

Die realisierte Lösung kann gut als Ausgangspunkt für weitere Projekte genutzt werden. Hierbei können unter anderem nachfolgende Arbeiten durchgeführt werden.

\begin{itemize}
	\item Speicher- und Laufzeitoptimierung der Bildverarbeitung.
	\item Erweiterung der Vergleichsfunktion um neue Bewertungskriterien.
	\item Substituieren der Webcam durch die Tiefensensorkamera \textit{Kinect}.
	\item Adaption der Hard- und Software zur Erkennung dreidimensionaler Objekte.
	\item Bestimmung der realen Objektposition anhand des aufgenommenen Kamerabildes und der Roboterlage (Position und Orientierung), so dass Objekte nicht wiederholt erkannt werden.
\end{itemize}





